home *** CD-ROM | disk | FTP | other *** search
/ ShareWare OnLine 2 / ShareWare OnLine Volume 2 (CMS Software)(1993).iso / os2 / remin301.zip / REMIN300.ZIP / USERFNS.C < prev    next >
C/C++ Source or Header  |  1992-11-10  |  11KB  |  346 lines

  1. /***************************************************************/
  2. /*                                                             */
  3. /*  USERFNS.C                                                  */
  4. /*                                                             */
  5. /*  This file contains the routines to support user-defined    */
  6. /*  functions.                                                 */
  7. /*                                                             */
  8. /*  This file is part of REMIND.                               */
  9. /*  Copyright (C) 1992 by David F. Skoll.                      */
  10. /*                                                             */
  11. /***************************************************************/
  12. #include "config.h"
  13. #include <stdio.h>
  14. #ifdef HAVE_STDLIB_H
  15. #include <stdlib.h>
  16. #endif
  17. #ifdef HAVE_MALLOC_H
  18. #include <malloc.h>
  19. #endif
  20. #include <ctype.h>
  21. #include "types.h"
  22. #include "globals.h"
  23. #include "protos.h"
  24. #include "err.h"
  25. #include "expr.h"
  26.  
  27. #define FUNC_HASH_SIZE 32   /* Size of User-defined function hash table */
  28.  
  29. /* Define the data structure used to hold a user-defined function */
  30. typedef struct _udf_struct {
  31.    struct _udf_struct *next;
  32.    char name[VAR_NAME_LEN+1];
  33.    char *text;
  34.    Var *locals;
  35.    char IsCached;
  36.    char IsActive;
  37.    int nargs;
  38. } UserFunc;
  39.  
  40. /* The hash table */
  41. static UserFunc *FuncHash[FUNC_HASH_SIZE];
  42.  
  43. /* We need access to the expression evaluation stack */
  44. extern Value ValStack[];
  45. extern int ValStackPtr;
  46.  
  47. PRIVATE void DestroyUserFunc ARGS ((UserFunc *f));
  48. PRIVATE void FUnset ARGS ((char *name));
  49. PRIVATE void FSet ARGS ((UserFunc *f));
  50. PRIVATE int SetUpLocalVars ARGS ((UserFunc *f));
  51. PRIVATE void DestroyLocalVals ARGS ((UserFunc *f));
  52.  
  53. /***************************************************************/
  54. /*                                                             */
  55. /*  DoFset                                                     */
  56. /*                                                             */
  57. /*  Define a user-defined function - the FSET command.         */
  58. /*                                                             */
  59. /***************************************************************/
  60. #ifdef HAVE_PROTOS
  61. PUBLIC int DoFset(ParsePtr p)
  62. #else
  63. int DoFset(p)
  64. ParsePtr p;
  65. #endif
  66. {
  67.    int r;
  68.    int c;
  69.    UserFunc *func;
  70.    Var *v;
  71.  
  72.    /* Get the function name */
  73.    if(r=ParseIdentifier(p, TokBuffer)) return r;
  74.  
  75.    /* Should be followed by '(' */
  76.    c = ParseNonSpaceChar(p, &r, 0);
  77.    if (r) return r;
  78.    if (c != '(') return E_PARSE_ERR;
  79.  
  80.    func = NEW(UserFunc);
  81.    if (!func) return E_NO_MEM;
  82.    StrnCpy(func->name, TokBuffer, VAR_NAME_LEN);
  83.    func->locals = NULL;
  84.    func->text = NULL;
  85.    func->IsCached = 1;
  86.    func->IsActive = 0;
  87.    func->nargs = 0;
  88.  
  89.    /* Get the local variables - we insert the local variables in REVERSE
  90.       order, but that's OK, because we pop them off the stack in reverse
  91.       order, too, so everything works out just fine. */
  92.  
  93.    c=ParseNonSpaceChar(p, &r, 1);
  94.    if (r) return r;
  95.    if (c == ')') {
  96.       (void) ParseNonSpaceChar(p, &r, 0);
  97.    }
  98.    else {
  99.       while(1) {
  100.      if (r=ParseIdentifier(p, TokBuffer)) return r;
  101.      v = NEW(Var);
  102.      func->nargs++;
  103.      v->v.type = ERR_TYPE;
  104.      if (!v) {
  105.         DestroyUserFunc(func);
  106.         return E_NO_MEM;
  107.      }
  108.      StrnCpy(v->name, TokBuffer, VAR_NAME_LEN);
  109.      v->next = func->locals;
  110.      func->locals = v;
  111.      c = ParseNonSpaceChar(p, &r, 0);
  112.      if (c == ')') break;
  113.      else if (c != ',') {
  114.         DestroyUserFunc(func);
  115.         return E_PARSE_ERR;
  116.      }
  117.       }
  118.    }
  119.  
  120.    /* Copy the text over */
  121.    if (p->isnested) {
  122.       Eprint ("Can't nest function definition in expression.");
  123.       DestroyUserFunc(func);
  124.       return E_PARSE_ERR;
  125.    }
  126.  
  127.    /* A bit of trickery here - if the definition is already cached,
  128.       no point in copying it. */
  129.    if (CurLine != LineBuffer) {
  130.       func->IsCached = 1;
  131.       func->text = p->pos;
  132.    } else {
  133.       func->IsCached = 0;
  134.       func->text = StrDup(p->pos);
  135.       if (!func->text) {
  136.      DestroyUserFunc(func);
  137.      return E_NO_MEM;
  138.       }
  139.    }
  140.  
  141.    /* If an old definition of this function exists, destroy it */
  142.    FUnset(func->name);
  143.  
  144.    /* Add the function definition */
  145.    FSet(func);
  146.    return OK;
  147. }
  148.  
  149. /***************************************************************/
  150. /*                                                             */
  151. /*  DestroyUserFunc                                            */
  152. /*                                                             */
  153. /*  Free up all the resources used by a user-defined function. */
  154. /*                                                             */
  155. /***************************************************************/
  156. #ifdef HAVE_PROTOS
  157. PRIVATE void DestroyUserFunc(UserFunc *f)
  158. #else
  159. static void DestroyUserFunc(f)
  160. UserFunc *f;
  161. #endif
  162. {
  163.    Var *v, *prev;
  164.  
  165.    /* Free the local variables first */
  166.    v = f->locals;
  167.    while(v) {
  168.       DestroyValue(&(v->v));
  169.       prev = v;
  170.       v = v->next;
  171.       free(prev);
  172.    }
  173.  
  174.    /* Free the function definition */
  175.    if (f->text && !f->IsCached) free(f->text);
  176.  
  177.    /* Free the data structure itself */
  178.    free(f);
  179. }
  180.  
  181. /***************************************************************/
  182. /*                                                             */
  183. /*  FUnset                                                     */
  184. /*                                                             */
  185. /*  Delete the function definition with the given name, if     */
  186. /*  it exists.                                                 */
  187. /*                                                             */
  188. /***************************************************************/
  189. #ifdef HAVE_PROTOS
  190. PRIVATE void FUnset(char *name)
  191. #else
  192. static void FUnset(name)
  193. char *name;
  194. #endif
  195. {
  196.    UserFunc *cur, *prev;
  197.    int h;
  198.  
  199.    h = HashVal(name) % FUNC_HASH_SIZE;
  200.  
  201.    cur = FuncHash[h];
  202.    prev = NULL;
  203.    while(cur) {
  204.       if (StrinEq(name, cur->name, VAR_NAME_LEN)) break;
  205.       prev = cur;
  206.       cur = cur->next;
  207.    }
  208.    if (!cur) return;
  209.    if (prev) prev->next = cur->next; else FuncHash[h] = cur->next;
  210.    DestroyUserFunc(cur);
  211. }
  212.  
  213. /***************************************************************/
  214. /*                                                             */
  215. /*  FSet                                                       */
  216. /*                                                             */
  217. /*  Insert a user-defined function into the hash table.        */
  218. /*                                                             */
  219. /***************************************************************/
  220. #ifdef HAVE_PROTOS
  221. PRIVATE void FSet(UserFunc *f)
  222. #else
  223. static void FSet(f)
  224. UserFunc *f;
  225. #endif
  226. {
  227.    int h = HashVal(f->name) % FUNC_HASH_SIZE;
  228.    f->next = FuncHash[h];
  229.    FuncHash[h] = f;
  230. }
  231.  
  232. /***************************************************************/
  233. /*                                                             */
  234. /*  CallUserFunc                                               */
  235. /*                                                             */
  236. /*  Call a user-defined function.                              */
  237. /*                                                             */
  238. /***************************************************************/
  239. #ifdef HAVE_PROTOS
  240. PUBLIC int CallUserFunc(char *name, int nargs)
  241. #else
  242. int CallUserFunc(name, nargs)
  243. char *name;
  244. int nargs;
  245. #endif
  246. {
  247.    UserFunc *f;
  248.    int h = HashVal(name) % FUNC_HASH_SIZE;
  249.    int i;
  250.    char *s;
  251.  
  252.    /* Search for the function */
  253.    f = FuncHash[h];
  254.    while (f && !StrinEq(name, f->name, VAR_NAME_LEN)) f = f->next;
  255.    if (!f) return E_UNDEF_FUNC;
  256.  
  257.    /* Debugging stuff */
  258.    if (DebugFlag & DB_PRTEXPR) {
  259.       fprintf(ErrFp, "UserFN %s(", f->name);
  260.       for (i=0; i<nargs; i++) {
  261.          PrintValue(&ValStack[ValStackPtr - nargs + i], ErrFp);
  262.          if (i<nargs-1) fprintf(ErrFp, ", ");
  263.       }
  264.       fprintf(ErrFp, ")\n");
  265.    }
  266.    /* Detect illegal recursive call */
  267.    if (f->IsActive) return E_RECURSIVE;
  268.  
  269.    /* Check number of args */
  270.    if (nargs != f->nargs)
  271.       return (nargs < f->nargs) ? E_2FEW_ARGS : E_2MANY_ARGS;
  272.  
  273.    /* Found the function - set up a local variable frame */
  274.    h = SetUpLocalVars(f);
  275.    if (h) return h;
  276.  
  277.    /* Evaluate the expression */
  278.    f->IsActive = 1;
  279.    s = f->text;
  280.  
  281.    /* Skip the opening bracket, if there's one */
  282.    while (isspace(*s)) s++;
  283.    if (*s == BEG_OF_EXPR) s++;
  284.    h = Evaluate(&s, f->locals);
  285.    f->IsActive = 0;
  286.    DestroyLocalVals(f);
  287.    if (DebugFlag &DB_PRTEXPR) {
  288.       fprintf(ErrFp, "Leaving UserFN %s() => ", name);
  289.       if (h) fprintf(ErrFp, "%s\n", ErrMsg[h]);
  290.       else {
  291.          PrintValue(&ValStack[ValStackPtr-1], ErrFp);
  292.          fprintf(ErrFp, "\n");
  293.       }
  294.    }
  295.    return h;
  296. }
  297.  
  298. /***************************************************************/
  299. /*                                                             */
  300. /*  SetUpLocalVars                                             */
  301. /*                                                             */
  302. /*  Set up the local variables from the stack frame.           */
  303. /*                                                             */
  304. /***************************************************************/
  305. #ifdef HAVE_PROTOS
  306. PRIVATE int SetUpLocalVars(UserFunc *f)
  307. #else
  308. static int SetUpLocalVars(f)
  309. UserFunc *f;
  310. #endif
  311. {
  312.    int i, r;
  313.    Var *var;
  314.  
  315.    for (i=0, var=f->locals; var && i<f->nargs; var=var->next, i++) {
  316.       if (r=PopValStack(&(var->v))) {
  317.      DestroyLocalVals(f);
  318.      return r;
  319.       }
  320.    }
  321.    return OK;
  322. }
  323.  
  324. /***************************************************************/
  325. /*                                                             */
  326. /*  DestroyLocalVals                                           */
  327. /*                                                             */
  328. /*  Destroy the values of all local variables after evaluating */
  329. /*  the function.                                              */
  330. /*                                                             */
  331. /***************************************************************/
  332. #ifdef HAVE_PROTOS
  333. PRIVATE void DestroyLocalVals(UserFunc *f)
  334. #else
  335. static void DestroyLocalVals(f)
  336. UserFunc *f;
  337. #endif
  338. {
  339.    Var *v = f->locals;
  340.  
  341.    while(v) {
  342.       DestroyValue(&(v->v));
  343.       v = v->next;
  344.    }
  345. }
  346.